#include "./timer.h"

using namespace MiniUI;

const wchar_t TimerWndClass[] = L"MiniUI_TIMER_CLASS";
static TimerWnd timerWnd;

//TimerWnd
TimerWnd::TimerWnd()
: m_hWnd(nullptr)
{
    WNDCLASSEX wc = {sizeof(wc)};
    wc.hInstance = ::GetModuleHandle(0);
    wc.lpszClassName = TimerWndClass;
    wc.lpfnWndProc = &TimerWndProc;
    wc.hbrBackground = 0;
    wc.cbWndExtra = sizeof(void*);
    RegisterClassEx(&wc);
    m_hWnd = CreateWindowEx(0, wc.lpszClassName, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, wc.hInstance, this);
}

TimerWnd::~TimerWnd()
{
    ::DestroyWindow(m_hWnd);
    UnregisterClass(TimerWndClass, ::GetModuleHandle(0));
}

HWND TimerWnd::GetHandle()
{
    return m_hWnd;
}

LRESULT TimerWnd::TimerWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
}

//Timer
Timer::Timer()
: Object("Timer")
, m_nInterval(1000)
, m_nID(0)
, m_customID(0)
, m_bStoped(false)
{
}

Timer::~Timer()
{
    Stop();
}

UINT Timer::GetTimerID() const
{
    return m_customID;
}

void Timer::Start(UINT nID)
{
    if (!m_nID)
    {
        Start();
        m_customID = nID;
    }
}

void Timer::Start()
{
    if (!m_nID)
    {
        m_nID = ::SetTimer(timerWnd.GetHandle(), (UINT_PTR)this, m_nInterval, (TIMERPROC)TimerProc);
        m_customID = m_nID;
        this->AddRef();
        m_bStoped = false;
    }
}

void Timer::Stop()
{
    if (m_nID)
    {
        ::KillTimer(timerWnd.GetHandle(), m_nID);
        m_nID = nullptr;
        m_customID = 0;
        m_bStoped = true;
    }
}

void Timer::SetInterval(uint nInterval)
{
    if (m_nInterval != nInterval)
    {
        m_nInterval = nInterval;
        if (m_nID)
        {
            ::KillTimer(timerWnd.GetHandle(), m_nID);
            m_nID = ::SetTimer(timerWnd.GetHandle(), (UINT_PTR)this, m_nInterval, (TIMERPROC)TimerProc);
        }
    }
}

void Timer::DoTimer()
{
    DoFireEvent(OnNotifyEventFunc, OnTimer, (this));
    if (m_bStoped)
    {
        this->Release();
    }
}

void Timer::TimerProc(HWND hWnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
{
    Timer* pTimer = (Timer*)idEvent;
    if (pTimer)
    {
        pTimer->DoTimer();
    }
}